﻿
using Boilen.Primitives.CodeGeneration;
using System;
using System.Collections.Generic;
using Xunit.Extensions;


namespace Boilen.Primitives.Implementers {

    public class TestEquatableInterface : TestImplementers {

        [Theory]
        [PropertyData( "SourceTypes" )]
        public void code_compiles_for_Equatable( Type sourceType ) {
            var pci1 = MemberTestInfo.Create<string>( "first" );
            var pci2 = MemberTestInfo.Create<string>( "second" );

            var pt = Partial.Type( sourceType )
                .AddImmutableProperty<string>( pci1.ParameterName, pci1.Description )
                .AddImmutableProperty<string>( pci2.ParameterName, pci2.Description )
                .ImplementIEquatable( pci1.ParameterName, pci2.ParameterName )
                .SetIsSealed( true )
                ;
            var members = Compile.PartialType( pt );
        }

        [Theory]
        [PropertyData( "SourceTypes" )]
        public void code_compiles_for_Equatable_with_external_documentation( Type sourceType ) {
            var pci1 = MemberTestInfo.Create<string>( "first" );
            var pci2 = MemberTestInfo.Create<string>( "second" );

            using( ChangeExternalDocumentationPrefix( ) ) {
                var pt = Partial.Type( sourceType )
                    .AddImmutableProperty<string>( pci1.ParameterName )
                    .AddImmutableProperty<string>( pci2.ParameterName )
                    .ImplementIEquatable( pci1.ParameterName, pci2.ParameterName )
                    .SetIsSealed( true )
                    ;
                var members = Compile.PartialType( pt );
            }
        }

        [Theory]
        [PropertyData( "SourceTypes" )]
        public void code_compiles_for_Equatable_with_custom_implementation( Type sourceType ) {
            var pci1 = MemberTestInfo.Create<string>( "value" );

            var pt = Partial.Type( sourceType )
                .AddImmutableProperty<string>( pci1.ParameterName, pci1.Description )
                .ImplementIEquatable( new[] { pci1.ParameterName }, i => i
                    .SetEqualsImplementation( Implementation.AutoAndCustom )
                    .SetGetHashCodeImplementation( Implementation.AutoAndCustom )
                    .SetVerifyExactType( true )
                )
                .SetIsSealed( true )
                ;
            var members = Compile.PartialType( pt );
        }

        [Theory]
        [PropertyData( "SourceTypes" )]
        public void code_compiles_for_Equatable_with_custom_FormatSelector( Type sourceType ) {
            var pci1 = MemberTestInfo.Create<string>( "value" );

            var pt = Partial.Type( sourceType )
                .AddImmutableProperty<string>( pci1.ParameterName, pci1.Description )
                .ImplementIEquatable( new[] { pci1.ParameterName }, i => i
                    .SetFormatSelector( ( p, e ) => e ? "StringComparer.Ordinal.Equals(this.{1}, {0}.{1})" : "StringComparer.Ordinal.GetHashCode({0})" )
                )
                .SetIsSealed( true )
                ;
            var members = Compile.PartialType( pt );
        }


        [Theory]
        [InlineData( typeof( BaseClass ) )]
        public void code_compiles_for_Equatable_on_derived_class( Type sourceType ) {
            var pci = MemberTestInfo.Create<int>( "intProperty", -1 );
            var required = MemberTestInfo.Create<int>( "requiredProperty" );
            var optional = MemberTestInfo.Create<int>( "optionalProperty" );

            var pt = Partial.Type( "DerivedClass", sourceType )
                .AddImmutableProperty<int>( pci.ParameterName, pci.Description, p => p
                    .SetDefaultValue( pci.DefaultValue )
                )
                .ImplementIEquatable( null )
                ;
            var members = Compile.PartialType( pt );
        }

        [Theory]
        [InlineData( typeof( BaseClass ) )]
        public void code_compiles_for_Equatable_on_derived_class_with_external_documentation( Type sourceType ) {
            var pci = MemberTestInfo.Create<int>( "intProperty", -1 );
            var required = MemberTestInfo.Create<int>( "requiredProperty" );
            var optional = MemberTestInfo.Create<int>( "optionalProperty" );

            using( ChangeExternalDocumentationPrefix( ) ) {
                var pt = Partial.Type( "DerivedClass", sourceType )
                    .AddImmutableProperty<int>( pci.ParameterName, p => p
                        .SetDefaultValue( pci.DefaultValue )
                    )
                    .ImplementIEquatable( null )
                    ;
                var members = Compile.PartialType( pt );
            }
        }


        public static IEnumerable<object[]> SourceTypes { get { return SourceTypesCore; } }

    }

}
